package com.yang.thread;

import java.util.ArrayList;
import java.util.List;

/**
 * wait/notify机制示例
 * 演示线程间的通信和协作
 */
public class WaitNotifyExample {
    
    public static void main(String[] args) {
        System.out.println("=== wait/notify机制示例 ===");
        
        // 1. 简单的等待通知示例
        demonstrateBasicWaitNotify();
        
        // 2. 生产者消费者模式（使用wait/notify实现）
        demonstrateProducerConsumerWithWaitNotify();
    }
    
    /**
     * 基础wait/notify示例
     */
    private static void demonstrateBasicWaitNotify() {
        System.out.println("\n--- 基础wait/notify示例 ---");
        
        SharedResource resource = new SharedResource();
        
        // 等待线程
        Thread waiter = new Thread(() -> {
            synchronized (resource) {
                try {
                    System.out.println("等待线程: 开始等待...");
                    resource.wait(); // 释放锁并等待
                    System.out.println("等待线程: 收到通知，继续执行");
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            }
        }, "Waiter");
        
        // 通知线程
        Thread notifier = new Thread(() -> {
            try {
                Thread.sleep(2000); // 等待2秒
                
                synchronized (resource) {
                    System.out.println("通知线程: 发送通知");
                    resource.notify(); // 唤醒等待的线程
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }, "Notifier");
        
        waiter.start();
        notifier.start();
        
        try {
            waiter.join();
            notifier.join();
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
    }
    
    /**
     * 使用wait/notify实现生产者消费者模式
     */
    private static void demonstrateProducerConsumerWithWaitNotify() {
        System.out.println("\n--- 使用wait/notify的生产者消费者模式 ---");
        
        Buffer buffer = new Buffer(5); // 容量为5的缓冲区
        
        // 创建生产者线程
        Thread producer1 = new Thread(new BufferProducer(buffer, "生产者1", 8), "Producer1");
        Thread producer2 = new Thread(new BufferProducer(buffer, "生产者2", 6), "Producer2");
        
        // 创建消费者线程
        Thread consumer1 = new Thread(new BufferConsumer(buffer, "消费者1"), "Consumer1");
        Thread consumer2 = new Thread(new BufferConsumer(buffer, "消费者2"), "Consumer2");
        
        // 启动所有线程
        producer1.start();
        producer2.start();
        consumer1.start();
        consumer2.start();
        
        try {
            // 等待生产者完成
            producer1.join();
            producer2.join();
            
            // 等待一段时间让消费者处理完
            Thread.sleep(3000);
            
            // 中断消费者
            consumer1.interrupt();
            consumer2.interrupt();
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
        }
        
        System.out.println("wait/notify示例结束");
    }
}

/**
 * 共享资源类
 */
class SharedResource {
    // 这个类只是作为同步对象使用
}

/**
 * 缓冲区类 - 使用wait/notify实现同步
 */
class Buffer {
    private final List<String> items;
    private final int capacity;
    
    public Buffer(int capacity) {
        this.capacity = capacity;
        this.items = new ArrayList<>();
    }
    
    /**
     * 生产方法 - 当缓冲区满时等待
     */
    public synchronized void produce(String item, String producerName) throws InterruptedException {
        // 当缓冲区满时等待
        while (items.size() >= capacity) {
            System.out.println(producerName + ": 缓冲区已满，等待消费...");
            wait(); // 释放锁并等待
        }
        
        // 添加产品到缓冲区
        items.add(item);
        System.out.println(producerName + ": 生产了 " + item + 
                          " [缓冲区大小: " + items.size() + "/" + capacity + "]");
        
        // 通知等待的消费者
        notifyAll();
    }
    
    /**
     * 消费方法 - 当缓冲区空时等待
     */
    public synchronized String consume(String consumerName) throws InterruptedException {
        // 当缓冲区空时等待
        while (items.isEmpty()) {
            System.out.println(consumerName + ": 缓冲区为空，等待生产...");
            wait(); // 释放锁并等待
        }
        
        // 从缓冲区取出产品
        String item = items.remove(0);
        System.out.println(consumerName + ": 消费了 " + item + 
                          " [缓冲区大小: " + items.size() + "/" + capacity + "]");
        
        // 通知等待的生产者
        notifyAll();
        
        return item;
    }
    
    public synchronized int size() {
        return items.size();
    }
}

/**
 * 缓冲区生产者
 */
class BufferProducer implements Runnable {
    private final Buffer buffer;
    private final String producerName;
    private final int itemCount;
    
    public BufferProducer(Buffer buffer, String producerName, int itemCount) {
        this.buffer = buffer;
        this.producerName = producerName;
        this.itemCount = itemCount;
    }
    
    @Override
    public void run() {
        try {
            for (int i = 1; i <= itemCount; i++) {
                String item = producerName + "-物品" + i;
                buffer.produce(item, producerName);
                
                // 模拟生产时间
                Thread.sleep(500 + (int)(Math.random() * 1000));
            }
            
            System.out.println(producerName + ": 生产完毕，共生产 " + itemCount + " 个物品");
            
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println(producerName + ": 被中断");
        }
    }
}

/**
 * 缓冲区消费者
 */
class BufferConsumer implements Runnable {
    private final Buffer buffer;
    private final String consumerName;
    
    public BufferConsumer(Buffer buffer, String consumerName) {
        this.buffer = buffer;
        this.consumerName = consumerName;
    }
    
    @Override
    public void run() {
        try {
            while (!Thread.currentThread().isInterrupted()) {
                String item = buffer.consume(consumerName);
                
                // 模拟消费时间
                Thread.sleep(800 + (int)(Math.random() * 1200));
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            System.out.println(consumerName + ": 被中断，停止消费");
        }
    }
}
